package com.seadragon.apps.doctorcard.controller;

import static com.seadragon.apps.doctorcard.model.DoctorCardConstants.*;


import java.security.Principal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;

import net.sf.json.JSONObject;

import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.socket.TextMessage;

import com.seadragon.apps.doctorcard.model.Chat;
import com.seadragon.apps.doctorcard.model.ChatContact;
import com.seadragon.apps.doctorcard.model.Contact;
import com.seadragon.apps.doctorcard.model.DoctorCardResult;
import com.seadragon.apps.doctorcard.model.Friend;
import com.seadragon.apps.doctorcard.model.Message;
import com.seadragon.apps.doctorcard.model.Request;
import com.seadragon.apps.doctorcard.model.RequestStatus;
import com.seadragon.apps.doctorcard.service.ChatMessageService;
import com.seadragon.apps.doctorcard.service.ChatService;
import com.seadragon.apps.doctorcard.service.ContactService;
import com.seadragon.apps.doctorcard.service.FriendService;
import com.seadragon.apps.doctorcard.service.RequestService;


@Controller
public class ContactController {
	private static Logger logger = LoggerFactory.getLogger(ContactController.class);

	private SimpMessagingTemplate template;
	
	@Autowired
	private ContactService contactService;

	@Autowired
	private ChatService chatService;

	@Autowired
	private ChatMessageService chatMessageService;

	@Autowired
	private RequestService requestService;

	@Autowired
	private FriendService friendService;

	@Autowired
    @Qualifier("contactValidator")
    private Validator contactValidator;

	@Autowired
    @Qualifier("messageValidator")
    private Validator messagevalidator;
 
	@Autowired
	public ContactController(SimpMessagingTemplate template){
		this.template = template;
	}
	
    @InitBinder
    private void initBinder(WebDataBinder binder) {
    	if(binder.getTarget() instanceof Contact){
    		binder.setValidator(contactValidator);
    	}
    	if(binder.getTarget() instanceof Message){
    		binder.setValidator(messagevalidator);
    	}
    }
    
	@RequestMapping(value = {"/contact/profile/save.json"}, method = RequestMethod.POST)
	@ResponseBody
	public DoctorCardResult saveContactProfileJson(@Valid @RequestBody Contact contact, BindingResult result, HttpSession session) {
		DoctorCardResult doctorCardResult = new DoctorCardResult();
		
		if(result.hasErrors()){
			for(ObjectError error : result.getAllErrors()){
				doctorCardResult.addErrorCode(Integer.parseInt(error.getDefaultMessage()));
			}
			doctorCardResult.setStatus(RETURN_FAIL);
			return doctorCardResult;
		}

		if (contact.getId() > 0){
			Contact contactInSession = (Contact)session.getAttribute(SESSION_SCOPED_CONTACT);
			if(contact.getId() != contactInSession.getId()){
				doctorCardResult.setStatus(RETURN_FAIL);
				doctorCardResult.addErrorCode(ERROR_CODE_UPDATE_CONTACT_FAIL);
			}else{
				contactService.update(contact);
				doctorCardResult.setStatus(RETURN_SUCCESS);
				doctorCardResult.setLoginedContact(contact);
				session.setAttribute(SESSION_SCOPED_CONTACT, contact);
			}
		}else{
			if(contactService.isContactExisted(contact)){
				doctorCardResult.setStatus(RETURN_FAIL);
				doctorCardResult.addErrorCode(ERROR_CODE_CONTACT_ALREADY_EXIST);
			}else{
				contact = contactService.save(contact);
				if(contact != null){
					doctorCardResult.setStatus(RETURN_SUCCESS);
					session.setAttribute(SESSION_SCOPED_CONTACT, contact);
					doctorCardResult.setLoginedContact(contact);
				}else{
					doctorCardResult.setStatus(RETURN_FAIL);
					doctorCardResult.addErrorCode(ERROR_CODE_FAIL_TO_SAVE_CONTACT);
				}
			}
		}
		return doctorCardResult;
	}	

	@RequestMapping(value = {"/contact/profile/get.json"}, method = RequestMethod.GET)
	public @ResponseBody
	DoctorCardResult getContactProfileJson(HttpServletRequest request, HttpSession session) {
		DoctorCardResult result = new DoctorCardResult();
		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			result.setStatus(RETURN_SUCCESS);
			result.setData(contactInSession);
			result.setLoginedContact(contactInSession);
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
		}
		return result;
	}
	
	@RequestMapping(value = "/contact/{checkType}/check-availability.json", method = RequestMethod.POST)
	public @ResponseBody
	JSONObject checkUserIdentifierAvailablity(@RequestBody Map<String,String> json,HttpSession session,@PathVariable String checkType) {
		JSONObject response = new JSONObject();
		JSONObject jsonObj = JSONObject.fromObject(json);
		String value = jsonObj.getString("value");
		boolean existed = false;
		if ("email".equals(checkType)){
			existed=contactService.isEmailExisted(value,(Contact)session.getAttribute(SESSION_SCOPED_CONTACT));
		} else if ("doctorcardid".equals(checkType)){
			existed=contactService.isDoctorCardIdExisted(value,(Contact)session.getAttribute(SESSION_SCOPED_CONTACT));
		} else if ("mobile".equals(checkType)){
			existed=contactService.isMobileExisted(value,(Contact)session.getAttribute(SESSION_SCOPED_CONTACT));
		}
		response.put("isValid", !existed);
		response.put("value",value);
		return response;
	}
	
	// Customer can login with DoctorCardId or Mobile or Email with the password.
	/**
	 * @param session
	 * @param request
	 * @param userInfo
	 * @return
	 */
	@RequestMapping(value = "/contact/login.json", method = RequestMethod.POST)
	public @ResponseBody
	DoctorCardResult loginJson(HttpSession session, ServletRequest request,@RequestBody Map<String, String> userInfo) {
		DoctorCardResult result = new DoctorCardResult();
		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			session.removeAttribute(SESSION_SCOPED_CONTACT);
		}
		Contact contact = contactService.login(userInfo.get(INPUT_USERNAME), userInfo.get(INPUT_PASSWORD));
		if(contact == null){
			result.setStatus(RETURN_FAIL);
		}else{
			session.setAttribute(SESSION_SCOPED_CONTACT, contact);
			result.setStatus(RETURN_SUCCESS);
			result.setLoginedContact(contact);
		}
		
		return result;
	}
	
	@RequestMapping(value = "/contact/forgot-password.json", method = RequestMethod.POST)
	public @ResponseBody
	DoctorCardResult forgotPasswordJson(HttpSession session, ServletRequest request,@RequestBody Map<String, String> infoMap) {
		String email = infoMap.get(INPUT_EMAIL);
		String lang = infoMap.get(INPUT_LANG);
		String resetPasswordUrl = infoMap.get(INPUT_RESET_PASSWORD_URL);
		
		DoctorCardResult result = new DoctorCardResult();
		if(email == null || email.length() == 0){
			result.addErrorCode(ERROR_CODE_FORGOT_PASSWORD_EMAIL_EMPTY);
			result.setStatus(RETURN_FAIL);
		}else{
			Contact contact = contactService.forgotPassword(email);
			if(contact != null){
				if(LANG_EN_US.equals(lang)){
					String message = FORGOT_PASSWORD_EMAIL_EN.replaceAll("\\{\\{resetPasswordUrl\\}\\}", resetPasswordUrl).replaceAll("\\{\\{token\\}\\}", contact.getToken());
					sendEmail(contact.getEmail(), contact.getName(), "Reset your password on Doctor Card!", message.toString());			
				}else if(LANG_ZH_CN.equals(lang)){
					String message = FORGOT_PASSWORD_EMAIL_EN.replaceAll("\\{\\{resetPasswordUrl\\}\\}", resetPasswordUrl).replaceAll("\\{\\{token\\}\\}", contact.getToken());
					sendEmail(contact.getEmail(), contact.getName(), "在名片博士上重置密码!", message.toString());			
				}
				result.setStatus(RETURN_SUCCESS);
			}else{
				result.setStatus(RETURN_FAIL);
			}
		}
		return result;
	}
	
	@RequestMapping(value = "/contact/logout.json", method = RequestMethod.GET)
	public @ResponseBody DoctorCardResult logout(HttpSession session) {
		DoctorCardResult result = new DoctorCardResult();
		session.removeAttribute(SESSION_SCOPED_CONTACT);
		result.setStatus(RETURN_SUCCESS);
		return result;
	}

	@RequestMapping(value = {"/contact/reset-password.json"}, method = RequestMethod.POST)
	public @ResponseBody
	DoctorCardResult resetPasswordJson(HttpServletRequest request, HttpSession session, @RequestBody Map<String, String> userInfo ) {
		DoctorCardResult result = new DoctorCardResult();
		String password = userInfo.get(INPUT_PASSWORD);
		String token = userInfo.get(INPUT_TOKEN);
		
		int returnCode = contactService.resetPassword(token, password);
		if(RETURN_SUCCESS == returnCode){
			result.setStatus(RETURN_SUCCESS);
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(returnCode);
		}
		
		return result;
	}	
	
	@RequestMapping(value = "/contact/change-password.json", method = RequestMethod.POST)
	@ResponseBody
	public DoctorCardResult changePassword(@RequestBody Map<String, String> passwords,HttpSession session) {
		DoctorCardResult result = new DoctorCardResult();
		String oldPassword = passwords.get("oldPassword");
		String newPassword = passwords.get("newPassword");

		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			result = contactService.changePassword(contactInSession, oldPassword, newPassword);
			if(result.getStatus() == RETURN_SUCCESS){
				session.setAttribute(SESSION_SCOPED_CONTACT, result.getLoginedContact());
			}
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
		}		
		return result;
	}	

	/**
	 * After find a contact, you click on Add, it will send a request to recipient.
	 */
	@RequestMapping(value = {"/contact/contacts/{contactId}/send-request.json"}, method = RequestMethod.POST)
	public @ResponseBody
	DoctorCardResult sendRequestJson(HttpServletRequest request, HttpSession session, @PathVariable int contactId, @RequestBody Request dcRequest) {
		DoctorCardResult result = new DoctorCardResult();
		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			dcRequest.setRecipient(new Contact(contactId));
			int returnCode = requestService.sendRequest(contactInSession, dcRequest);
			if(RETURN_SUCCESS == returnCode){
				result.setStatus(RETURN_SUCCESS);
				result.setLoginedContact(contactInSession);
			}else{
				result.setStatus(RETURN_FAIL);
				result.addErrorCode(ERROR_CODE_FAIL_TO_SAVE_REQUEST);
				result.setLoginedContact(contactInSession);
			}
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
		}
		return result;
	}	

	/**
	 * Accept a request, it means there are friends.
	 */
	@RequestMapping(value = {"/contact/contacts/{contactId}/accept-request.json"}, method = RequestMethod.GET)
	public @ResponseBody
	DoctorCardResult acceptRequestJson(HttpServletRequest request, HttpSession session, @PathVariable int contactId) {
		DoctorCardResult result = new DoctorCardResult();
		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			int returnCode = requestService.acceptRequest(contactInSession, new Request(new Contact(contactId), contactInSession));
			if(returnCode == RETURN_SUCCESS){
				result.setStatus(RETURN_SUCCESS);
			}else{
				result.setStatus(RETURN_FAIL);
				result.addErrorCode(returnCode);
			}
			result.setLoginedContact(contactInSession);
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
		}
		return result;
	}

	@RequestMapping(value = {"/contact/contacts/search.json"}, method = RequestMethod.POST)
	public @ResponseBody
	DoctorCardResult searchContactsJson(HttpServletRequest request, HttpSession session, @RequestBody Map<String, String> keywordMap) {
		DoctorCardResult result = new DoctorCardResult();
		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			List<Contact> contacts = contactService.search(contactInSession, keywordMap.get(INPUT_KEYWORD));
			result.setStatus(RETURN_SUCCESS);
			result.setData(contacts);
			result.setLoginedContact(contactInSession);
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
		}
		return result;
	}

	// Get a contact profile from own contact list.
	@RequestMapping(value = {"/contact/contacts/{contactId}/profile/get.json"}, method = RequestMethod.GET)
	public @ResponseBody
	DoctorCardResult getContactProfileThroughContactsJson(HttpServletRequest request, HttpSession session, @PathVariable int contactId) {
		DoctorCardResult result = new DoctorCardResult();
		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			Friend friend = friendService.findByTwoContacts(contactInSession, new Contact(contactId));
			if(friend == null){
				result.setStatus(RETURN_FAIL);
				result.addErrorCode(ERROR_CODE_NOT_YOUR_FRIEND);
			}else {
				result.setStatus(RETURN_SUCCESS);
				if(contactInSession.getId() == friend.getSender().getId()){
					result.setData(friend.getRecipient());
				}else{
					result.setData(friend.getSender());
				}
				result.setLoginedContact(contactInSession);
			}
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
		}
		return result;
	}	

	@RequestMapping(value = {"/contact/chats/get.json"}, method = RequestMethod.GET)
	public @ResponseBody
	DoctorCardResult getChatsJson(HttpServletRequest request, HttpSession session) {
		DoctorCardResult result = new DoctorCardResult();
		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			List<Chat> chats = chatService.findChatsByContact(contactInSession);
			result.setStatus(RETURN_SUCCESS);
			result.setData(chats);
			result.setLoginedContact(contactInSession);
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
		}
		return result;
	}

	// First get a list of chats, click on one of chats to display chat profile
	@RequestMapping(value = {"/contact/chats/{chatId}/profile/get.json"}, method = RequestMethod.GET)
	public @ResponseBody
	DoctorCardResult getChatProfileJson(HttpServletRequest request, HttpSession session,  @PathVariable int chatId, @PathVariable int contactId) {
		DoctorCardResult result = new DoctorCardResult();
		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			ChatContact cc = chatService.findByChatAndContact(new Chat(chatId), contactInSession);
			if(cc == null){
				result.setStatus(RETURN_FAIL);
				result.addErrorCode(ERROR_CODE_NOT_YOUR_CHAT);
			}else{
				result.setStatus(RETURN_SUCCESS);
				result.setData(cc.getChat());
			}
			result.setLoginedContact(contactInSession);
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
		}
		return result;
	}

	@RequestMapping(value = {"/contact/chats/{chatId}/{contactId}/profile/get.json"}, method = RequestMethod.GET)
	public @ResponseBody
	DoctorCardResult getContactProfileThroughChatJson(HttpServletRequest request, HttpSession session,  @PathVariable int chatId, @PathVariable int contactId) {
		DoctorCardResult result = new DoctorCardResult();
		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			if(chatService.isMemberOf(new Chat(chatId), contactInSession)){
				ChatContact cc = chatService.findByChatAndContact(new Chat(chatId), new Contact(contactId));
				if(cc == null){
					result.setStatus(RETURN_FAIL);
					result.addErrorCode(ERROR_CODE_CONTACT_NOT_IN_CHAT);
				}else{
					result.setStatus(RETURN_SUCCESS);
					result.setData(cc.getChat());
				}
			}else{
				result.setStatus(RETURN_FAIL);
				result.addErrorCode(ERROR_CODE_NOT_YOUR_CHAT);
			}
			result.setLoginedContact(contactInSession);			
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
			
		}
		return result;
	}	
	
	@RequestMapping(value = {"/contact/contacts/{contactId}/create-chat.json"}, method = RequestMethod.GET)
	public @ResponseBody
	DoctorCardResult createChatJson(HttpServletRequest request, HttpSession session, @PathVariable int contactId) {
		DoctorCardResult result = new DoctorCardResult();

		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			Chat chat = chatService.save(contactInSession, new Contact(contactId));
			if(chat == null){
				result.setStatus(RETURN_FAIL);
				result.addErrorCode(ERROR_CODE_FAIL_TO_SAVE_CHAT);
			}else{
				result.setStatus(RETURN_SUCCESS);
				result.setData(chat);
			}
			result.setLoginedContact(contactInSession);
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
		}
		return result;
	}
	
	@RequestMapping(value = {"/contact/chats/{chatId}/{contactId}/add-contact.json"}, method = RequestMethod.POST)
	public @ResponseBody
	DoctorCardResult addContactToChatJson(HttpServletRequest request, HttpSession session, @PathVariable int chatId, 
			@PathVariable int contactId) {
		DoctorCardResult result = new DoctorCardResult();

		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			int returnCode = chatService.add(contactInSession,  new Chat(chatId), new Contact(contactId));
			if(returnCode == RETURN_SUCCESS){
				result.setStatus(RETURN_SUCCESS);
			}else{
				result.setStatus(RETURN_FAIL);
				result.addErrorCode(returnCode);
			}
			result.setLoginedContact(contactInSession);			
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
		}
		return result;
	}

	@RequestMapping(value = {"/contact/contacts/get.json"}, method = RequestMethod.GET)
	public @ResponseBody
	DoctorCardResult getContactsJson(HttpServletRequest request, HttpSession session) {
		DoctorCardResult result = new DoctorCardResult();
		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			List<Contact> contacts= friendService.findByContact(contactInSession);
			result.setStatus(RETURN_SUCCESS);
			result.setData(contacts);
			result.setLoginedContact(contactInSession);			
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
			
		}
		return result;
	}

	
	@RequestMapping(value = {"/contact/requests/get.json"}, method = RequestMethod.GET)
	public @ResponseBody
	DoctorCardResult getRequestsJson(HttpServletRequest request, HttpSession session) {
		DoctorCardResult result = new DoctorCardResult();
		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			List<Contact> contacts = requestService.findAllRequests(contactInSession);
			result.setStatus(RETURN_SUCCESS);
			result.setData(contacts);
			result.setLoginedContact(contactInSession);			
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
			
		}
		return result;
	}
	
	@RequestMapping(value = {"/contact/requests/get-requests-received-newly.json"}, method = RequestMethod.GET)
	public @ResponseBody
	DoctorCardResult getRequestsReceivedNewlyJson(HttpServletRequest request, HttpSession session) {
		DoctorCardResult result = new DoctorCardResult();
		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			List<Contact> contacts = requestService.findAllRequestsReceivedByStatus(contactInSession, RequestStatus.RequestSent);
			result.setStatus(RETURN_SUCCESS);
			result.setData(contacts);
			result.setLoginedContact(contactInSession);			
		}else{
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
			
		}
		return result;
	}
	
	@RequestMapping(value = {"/contact/contacts/{contactId}/remove-friend.json"}, method = RequestMethod.GET)
	public @ResponseBody
	DoctorCardResult removeFriendJson(HttpServletRequest request, HttpSession session, @PathVariable int contactId) {
		DoctorCardResult result = null;
		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			result = friendService.remove(contactInSession, new Contact(contactId));
			result.setLoginedContact(contactInSession);			
		}else{
			result = new DoctorCardResult();
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
		}
		return result;
	}
	
	@RequestMapping(value = {"/contact/chat/messages/get-messages.json"}, method = RequestMethod.POST)
	public @ResponseBody
	DoctorCardResult getChatMessagesJson(HttpServletRequest request, HttpSession session, @RequestBody Map<String, String> inputMap) {
		DoctorCardResult result = null;
		long chatId = Long.parseLong(inputMap.get(INPUT_CHAT_ID));
		int offset = Integer.parseInt(inputMap.get(INPUT_OFFSET));
		int pageSize = Integer.parseInt(inputMap.get(INPUT_PAGE_SIZE));

		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			if(chatService.isMemberOf(chatId, contactInSession)){
				result = chatMessageService.findMessagesByChat(contactInSession, chatId, offset, pageSize);
			}
		}else{
			result = new DoctorCardResult();
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
		}
		return result;
	}
	
	@RequestMapping(value = {"/contact/chats/{chatId}/send-message.json"}, method = RequestMethod.POST)
	public @ResponseBody
	DoctorCardResult sendMessagesJson(HttpServletRequest request, HttpSession session, @PathVariable int chatId, @RequestBody Message message) {
		DoctorCardResult result = null;

		if (session.getAttribute(SESSION_SCOPED_CONTACT) != null) {
			Contact contactInSession = (Contact )session.getAttribute(SESSION_SCOPED_CONTACT);
			result = chatMessageService.sendMessage(contactInSession, new Chat(chatId), message);
			result.setLoginedContact(contactInSession);			
		}else{
			result = new DoctorCardResult();
			result.setStatus(RETURN_FAIL);
			result.addErrorCode(ERROR_CODE_NOT_LOGINED);
		}
		return result;
	}
	

	private void sendEmail(String emailTo, String nameTo, String subject, String message){
		HtmlEmail email = new HtmlEmail();
		email.setAuthentication(DOCTOR_CARD_EMAIL_ADDRESS, DOCTOR_CARD_EMAIL_PASSWORD);
		email.setSmtpPort(GOOGLE_SMTP_SERVER_PORT);
		email.setHostName(GOOGLE_SMTP_SERVER);
		email.setSSLOnConnect(true);
		try{
			email.addTo(emailTo, nameTo);
			email.setFrom(DOCTOR_CARD_EMAIL_ADDRESS, DOCTOR_CARD_EMAIL_NAME);
			email.setSubject(subject);
			email.setHtmlMsg(message);
			email.send();
		}catch(EmailException ex){
			logger.error("Failed to create an email to " + emailTo, ex);
		}
	}

	@MessageMapping("/chat/{chatId}")
	public void sendMessage(@DestinationVariable long chatId, Message message) {
	    System.out.println("Send " + message + " to " + chatId);
	    long contactId = message.getPublisher().getId();
	    DoctorCardResult result = chatMessageService.sendMessage(new Contact(contactId), new Chat(chatId), message);
	    Map<String, String> messageMap = new HashMap<String, String>();
	    if(RETURN_SUCCESS == result.getStatus()){
	    	messageMap.put(OUTPUT_MEDIA_TYPE, message.getMediaType());
	    	messageMap.put(OUTPUT_MEDIA_CONTENT, message.getMediaContent());
	    	messageMap.put(CONTACT_ID, Long.toString(contactId));
		    template.convertAndSend("/topic/chat-" + chatId, messageMap);	    	
	    }else{
	    	template.convertAndSendToUser(Long.toString(contactId), "/queue/errors", "Fail to send messages!");
	    }
	}

	@MessageExceptionHandler
	@SendToUser("/queue/errors")
	public String handleException(Throwable exception) {
		return exception.getMessage();
	}

}
